<!doctype html>
<html lang="zh-CN">
 <head> 
  <meta charset="utf-8"> 
  <link rel="canonical" href="https://blog.csdn.net/m0_60608144/article/details/147110338"> 
  <meta http-equiv="content-type" content="text/html; charset=utf-8"> 
  <meta name="renderer" content="webkit"> 
  <meta name="force-rendering" content="webkit"> 
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> 
  <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> 
  <meta name="report" content="{&quot;pid&quot;: &quot;blog&quot;, &quot;spm&quot;:&quot;1001.2101&quot;}"> 
  <meta name="referrer" content="always"> 
  <meta http-equiv="Cache-Control" content="no-siteapp">
  <link rel="alternate" media="handheld" href="#">  
  <meta name="applicable-device" content="pc"> 
  <link href="https://g.csdnimg.cn/static/logo/favicon32.ico" rel="shortcut icon" type="image/x-icon"> 
  <title>C++/Qt导出动态数据生成Word、PDF报表文件_qt动态生成word-CSDN博客</title>   
  <meta name="keywords" content="qt动态生成word"> 
  <meta name="csdn-baidu-search" content="{&quot;autorun&quot;:true,&quot;install&quot;:true,&quot;keyword&quot;:&quot;qt动态生成word&quot;}"> 
  <meta name="description" content="文章浏览阅读1k次，点赞19次，收藏19次。C++/Qt使用QuaZip、libreoffice,配合自定义Word模板生成Word文件和Pdf文件_qt动态生成word"> 
  <link rel="stylesheet" type="text/css" href="https://csdnimg.cn/release/blogv2/dist/pc/css/detail_enter-5658c22085.min.css">  
  <link rel="stylesheet" type="text/css" href="https://csdnimg.cn/release/blogv2/dist/pc/themesSkin/skin-number/skin-number-2c93789924.min.css">    
  <meta name="toolbar" content="{&quot;type&quot;:&quot;0&quot;,&quot;fixModel&quot;:&quot;1&quot;}">    
  <link rel="stylesheet" type="text/css" href="https://csdnimg.cn/public/sandalstrap/1.4/css/sandalstrap.min.css"> 
  <style>
        .MathJax, .MathJax_Message, .MathJax_Preview{
            display: none
        }
    </style>      
 	<style>
	main div.blog-content-box pre {
		max-height: 100%;
		overflow-y: hidden;
	}
	</style>
 </head>  
 <body class="nodata  " style=""> 
  <div id="toolbarBox" style="min-height: 48px;"></div>    
  <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/pc/css/blog_code-01256533b5.min.css"> 
  <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/chart-3456820cac.css"> 
  <link rel="stylesheet" href="https://g.csdnimg.cn/lib/swiper/6.0.4/css/swiper.css">   
  <div class="main_father clearfix d-flex justify-content-center mainfather-concision" style="height:100%;"> 
   <div class="container clearfix container-concision" id="mainBox">  
    <main>  
     <div class="blog-content-box"> 
      <div class="article-header-box"> 
       <div class="article-header"> 
        <div class="article-title-box"> 
         <h1 class="title-article" id="articleContentId">C++/Qt导出动态数据生成Word、PDF报表文件</h1> 
        </div> 
        <div class="article-info-box"> 
         <div class="article-bar-top-box"> 
          <div class="article-bar-top"> 
           <img class="article-type-img" src="https://csdnimg.cn/release/blogv2/dist/pc/img/original.png" alt=""> 
           <div class="bar-content"> 
            <a href="https://mall.csdn.net/vip" data-report-query="spm=3001.10404" data-report-click="{&quot;spm&quot;:&quot;3001.10404&quot;}" data-report-view="{&quot;spm&quot;:&quot;3001.10404&quot;}" class="article-vip-box" target="_blank"><img class="article-vip-img-new" src="https://csdnimg.cn/release/blogv2/dist/pc/img/identityVipNew.png" alt=""></a> 
            <a class="follow-nickName " href="https://blog.csdn.net/m0_60608144" target="_blank" rel="noopener" title="终不似JHH">终不似JHH</a> 
            <img class="article-time-img article-heard-img" src="https://csdnimg.cn/release/blogv2/dist/pc/img/newCurrentTime2.png" alt=""> 
            <span class="time">于&nbsp;2025-04-10 10:40:47&nbsp;发布</span> 
            <div class="read-count-box"> 
             <img class="article-read-img article-heard-img" src="https://csdnimg.cn/release/blogv2/dist/pc/img/articleReadEyes2.png" alt=""> 
             <span class="read-count">阅读量1k</span> 
             <a id="blog_detail_zk_collection" class="un-collection" data-report-click="{&quot;mod&quot;:&quot;popu_823&quot;,&quot;spm&quot;:&quot;1001.2101.3001.4232&quot;,&quot;ab&quot;:&quot;new&quot;}"> <img class="article-collect-img article-heard-img un-collect-status isdefault" style="display:inline-block" src="https://csdnimg.cn/release/blogv2/dist/pc/img/tobarCollect2.png" alt=""> <img class="article-collect-img article-heard-img collect-status isactive" style="display:none" src="https://csdnimg.cn/release/blogv2/dist/pc/img/tobarCollectionActive2.png" alt=""> <span class="name">收藏</span> <span class="get-collection"> 19 </span> </a> 
             <div class="read-count-box is-like" data-type="top"> 
              <img class="article-read-img article-heard-img" style="display:none" id="is-like-imgactive-new" src="https://csdnimg.cn/release/blogv2/dist/pc/img/newHeart2023Active.png" alt=""> 
              <img class="article-read-img article-heard-img" style="display:block" id="is-like-img-new" src="https://csdnimg.cn/release/blogv2/dist/pc/img/newHeart2023Black.png" alt=""> 
              <span class="read-count" id="blog-digg-num">点赞数 19 </span> 
             </div> 
            </div> 
           </div> 
          </div> 
          <div class="operating"> 
           <a class="href-article-edit slide-toggle">CC 4.0 BY-SA版权</a> 
          </div> 
         </div> 
         <div class="blog-tags-box"> 
          <div class="tags-box artic-tag-box"> 
           <span class="label">文章标签：</span> 
           <a rel="noopener" data-report-query="spm=1001.2101.3001.4223" data-report-click="{&quot;mod&quot;:&quot;popu_626&quot;,&quot;spm&quot;:&quot;1001.2101.3001.4223&quot;,&quot;strategy&quot;:&quot;c++&quot;,&quot;ab&quot;:&quot;new&quot;,&quot;extra&quot;:&quot;{\&quot;searchword\&quot;:\&quot;c++\&quot;}&quot;}" data-report-view="{&quot;mod&quot;:&quot;popu_626&quot;,&quot;spm&quot;:&quot;1001.2101.3001.4223&quot;,&quot;strategy&quot;:&quot;c++&quot;,&quot;ab&quot;:&quot;new&quot;,&quot;extra&quot;:&quot;{\&quot;searchword\&quot;:\&quot;c++\&quot;}&quot;}" class="tag-link" href="https://so.csdn.net/so/search/s.do?q=c%2B%2B&amp;t=all&amp;o=vip&amp;s=&amp;l=&amp;f=&amp;viparticle=&amp;from_tracking_code=tag_word&amp;from_code=app_blog_art" target="_blank">c++</a> 
           <a rel="noopener" data-report-query="spm=1001.2101.3001.4223" data-report-click="{&quot;mod&quot;:&quot;popu_626&quot;,&quot;spm&quot;:&quot;1001.2101.3001.4223&quot;,&quot;strategy&quot;:&quot;qt&quot;,&quot;ab&quot;:&quot;new&quot;,&quot;extra&quot;:&quot;{\&quot;searchword\&quot;:\&quot;qt\&quot;}&quot;}" data-report-view="{&quot;mod&quot;:&quot;popu_626&quot;,&quot;spm&quot;:&quot;1001.2101.3001.4223&quot;,&quot;strategy&quot;:&quot;qt&quot;,&quot;ab&quot;:&quot;new&quot;,&quot;extra&quot;:&quot;{\&quot;searchword\&quot;:\&quot;qt\&quot;}&quot;}" class="tag-link" href="https://so.csdn.net/so/search/s.do?q=qt&amp;t=all&amp;o=vip&amp;s=&amp;l=&amp;f=&amp;viparticle=&amp;from_tracking_code=tag_word&amp;from_code=app_blog_art" target="_blank">qt</a> 
           <a rel="noopener" data-report-query="spm=1001.2101.3001.4223" data-report-click="{&quot;mod&quot;:&quot;popu_626&quot;,&quot;spm&quot;:&quot;1001.2101.3001.4223&quot;,&quot;strategy&quot;:&quot;word&quot;,&quot;ab&quot;:&quot;new&quot;,&quot;extra&quot;:&quot;{\&quot;searchword\&quot;:\&quot;word\&quot;}&quot;}" data-report-view="{&quot;mod&quot;:&quot;popu_626&quot;,&quot;spm&quot;:&quot;1001.2101.3001.4223&quot;,&quot;strategy&quot;:&quot;word&quot;,&quot;ab&quot;:&quot;new&quot;,&quot;extra&quot;:&quot;{\&quot;searchword\&quot;:\&quot;word\&quot;}&quot;}" class="tag-link" href="https://so.csdn.net/so/search/s.do?q=word&amp;t=all&amp;o=vip&amp;s=&amp;l=&amp;f=&amp;viparticle=&amp;from_tracking_code=tag_word&amp;from_code=app_blog_art" target="_blank">word</a> 
           <a rel="noopener" data-report-query="spm=1001.2101.3001.4223" data-report-click="{&quot;mod&quot;:&quot;popu_626&quot;,&quot;spm&quot;:&quot;1001.2101.3001.4223&quot;,&quot;strategy&quot;:&quot;pdf&quot;,&quot;ab&quot;:&quot;new&quot;,&quot;extra&quot;:&quot;{\&quot;searchword\&quot;:\&quot;pdf\&quot;}&quot;}" data-report-view="{&quot;mod&quot;:&quot;popu_626&quot;,&quot;spm&quot;:&quot;1001.2101.3001.4223&quot;,&quot;strategy&quot;:&quot;pdf&quot;,&quot;ab&quot;:&quot;new&quot;,&quot;extra&quot;:&quot;{\&quot;searchword\&quot;:\&quot;pdf\&quot;}&quot;}" class="tag-link" href="https://so.csdn.net/so/search/s.do?q=pdf&amp;t=all&amp;o=vip&amp;s=&amp;l=&amp;f=&amp;viparticle=&amp;from_tracking_code=tag_word&amp;from_code=app_blog_art" target="_blank">pdf</a> 
          </div> 
         </div> 
         <div class="slide-content-box"> 
          <div class="article-copyright"> 
           <div class="creativecommons">
             版权声明：本文为博主原创文章，遵循
            <a href="http://creativecommons.org/licenses/by-sa/4.0/" target="_blank" rel="noopener"> CC 4.0 BY-SA </a>版权协议，转载请附上原文出处链接和本声明。 
           </div> 
           <div class="article-source-link">
             本文链接：
            <a href="https://blog.csdn.net/m0_60608144/article/details/147110338" target="_blank">https://blog.csdn.net/m0_60608144/article/details/147110338</a> 
           </div> 
          </div> 
         </div> 
        </div> 
       </div> 
      </div> 
      <div id="blogHuaweiyunAdvert" class=""></div> 
      <article class="baidu_pl"> 
       <div id="article_content" class="article_content clearfix"> 
        <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/kdoc_html_views-1a98987dfd.css"> 
        <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/ck_htmledit_views-8d6d398833.css"> 
        <div id="content_views" class="htmledit_views atom-one-dark"> 
         <p>使用的是 <strong>Qt + C++</strong>，需要生成 <strong>PDF 和 Word 文档</strong>，且希望支持：</p> 
         <ul>
          <li> <p><strong>动态数据填充</strong></p> </li>
          <li> <p><strong>基于 Word 模板</strong></p> </li>
          <li> <p><strong>免费、开源或至少可免费使用</strong></p> </li>
          <li> <p><strong>跨平台支持（最好能兼容 Windows/Linux）</strong></p> </li>
         </ul> 
         <p>以下是几个适合的方案（根据你的要求排序）：</p> 
         <hr> 
         <h4>✅ <strong>首选方案：<code>libreoffice + C++ 调用</code >（配合 Word 模板）</strong></h4> 
         <h5>方案亮点：</h5> 
         <ul>
          <li> <p>使用 <code>.docx</code > 或 <code>.odt</code > 模板，通过 <strong>LibreOffice 的命令行模式</strong> 进行批量替换、生成 PDF。</p> </li>
          <li> <p>完全 <strong>免费、跨平台</strong>。</p> </li>
          <li> <p>模板中使用占位符（如 <code>${name}</code >），程序中替换内容。</p> </li>
          <li> <p>生成 PDF、Word 都可。</p> </li>
         </ul> 
         <h5>实现方式：</h5> 
         <ol>
          <li> <p>Word 模板使用占位符（如 <code>${DeviceName}</code >）。</p> </li>
          <li> <p>Qt 中用 C++ 替换模板中 XML（docx 实际是 zip 包），或用 Python/Pandoc 等脚本辅助。</p> </li>
          <li> <p>用 <code>LibreOffice</code > 命令行将 <code>.docx</code > 转 <code>.pdf</code >：</p> </li>
         </ol> 
         <pre><code class="hljs">libreoffice --headless --convert-to pdf yourfile.docx
</code ></pre> 
         <h5>C++ 示例逻辑：</h5> 
         <ul>
          <li> <p>用 <code>QuaZip</code >（或 <code>minizip</code >）解压 <code>.docx</code ></p> </li>
          <li> <p>用 <code>QDomDocument</code > 处理 XML（<code>word/document.xml</code >）</p> </li>
          <li> <p>替换占位符</p> </li>
          <li> <p>压缩回 <code>.docx</code ></p> </li>
         </ul> 
         <h5>优点：</h5> 
         <ul>
          <li> <p>样式完全可控（Word 设计好模板）</p> </li>
          <li> <p>自由度高，兼容 Word、PDF 输出</p> </li>
          <li> <p><strong>可从 Qt 完整自动化控制整个流程</strong></p> </li>
         </ul> 
         <h5>缺点：</h5> 
         <ul>
          <li> <p>需要安装 <code>LibreOffice</code ></p> </li>
          <li> <p>处理模板稍复杂，但一次性封装好即可复用</p> </li>
         </ul> 
         <hr> 
         <h3>🧱 一、实现原理概览</h3> 
         <ol>
          <li> <p>使用 <strong>Word 模板</strong>（<code>.docx</code >），设置 <strong>占位符</strong>（如 <code>${DeviceName}</code >）。</p> </li>
          <li> <p>Qt 程序中用 <strong>Zip 解压</strong> <code>.docx</code > 文件（实际是一个 zip 文件）。</p> </li>
          <li> <p>用 <strong>Qt DOM（<code>QDomDocument</code >）修改 XML 内容</strong>，替换占位符为实际值。</p> </li>
          <li> <p>再次打包为 <code>.docx</code >。</p> </li>
          <li> <p>使用 <strong>LibreOffice headless 模式</strong> 将 <code>.docx</code > 转换为 <code>.pdf</code >。</p> </li>
         </ol> 
         <hr> 
         <h3>📄 二、模板制作方法（用 Word 创建）</h3> 
         <ol>
          <li> <p>用 Word 新建一个模板文件，比如 <code>report_template.docx</code ></p> </li>
          <li> <p>在文本中加入占位符，如：</p> <pre><code class="hljs">设备名称：${DeviceName}
编程次数：${ProgramTimes}
错误次数：${ErrorCount}
</code ></pre> </li>
          <li> <p>可使用表格、图片、标题、页眉页脚等样式，美化文档结构。</p> </li>
          <li> <p>保存为 <code>.docx</code > 模板（可另存为 <code>template.docx</code >）</p> </li>
         </ol> 
         <hr> 
         <h3>🧰 三、依赖项</h3> 
         <h4>Qt 相关：</h4> 
         <ul>
          <li> <p><code>QtCore</code ></p> </li>
          <li> <p><code>QtXml</code ></p> </li>
          <li> <p>第三方库：<strong>QuaZip</strong> 或系统调用 unzip/zip 工具（推荐 QuaZip）</p> </li>
         </ul> 
         <h4>外部工具：</h4> 
         <ul>
          <li> <p>安装 <strong>LibreOffice</strong> 并确保其在命令行中可用（支持 <code>--headless</code >）</p> 
           <ul>
            <li> <p>Windows 默认安装路径如：<code>C:\Program Files\LibreOffice\program\soffice.exe</code ></p> </li>
            <li> <p>Linux/macOS 一般直接在 PATH 下有 <code>libreoffice</code ></p> </li>
           </ul> </li>
         </ul> 
         <hr> 
         <h3>🧪 四、完整代码示例（Qt C++）</h3> 
         <p>假设你已经有模板 <code>template.docx</code > 和待导出的目标文件 <code>report.docx</code ></p> 
         <h4>1. 替换占位符内容</h4> 
         <pre><code  style="height: 50vh;" class="hljs">#include &lt;QFile&gt;
#include &lt;QDomDocument&gt;
#include &lt;QProcess&gt;
#include &lt;QDir&gt;
#include &lt;QDebug&gt;
#include &lt;QTemporaryDir&gt;
#include &lt;QMap&gt;

bool replaceTextInDocx(const QString &amp;templatePath, const QString &amp;outputPath, const QMap&lt;QString, QString&gt; &amp;replacements) {
    QTemporaryDir tempDir;
    if (!tempDir.isValid()) return false;

    // Step 1: 解压 docx
    QString unzipPath = tempDir.path();
    QProcess::execute("unzip", { templatePath, "-d", unzipPath });

    QString docXmlPath = unzipPath + "/word/document.xml";
    QFile file(docXmlPath);
    if (!file.open(QIODevice::ReadOnly)) return false;

    QDomDocument doc;
    doc.setContent(&amp;file);
    file.close();

    // Step 2: 替换占位符
    QString xml = doc.toString();
    for (auto it = replacements.begin(); it != replacements.end(); ++it) {
        xml.replace("${" + it.key() + "}", it.value());
    }

    // Step 3: 保存 document.xml
    if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) return false;
    file.write(xml.toUtf8());
    file.close();

    // Step 4: zip 回 docx
    QDir::setCurrent(unzipPath);
    QProcess::execute("zip", { "-r", outputPath, "." });  // Windows 用户需安装 zip 工具或用 QuaZip 实现

    return true;
}
</code ></pre> 
         <hr> 
         <h4>2. 调用 LibreOffice 转 PDF</h4> 
         <pre><code class="hljs">bool convertDocxToPdf(const QString &amp;docxPath, const QString &amp;pdfOutputDir) {
    QProcess process;
    QString libreOfficeCmd = "libreoffice"; // 可根据平台判断改为绝对路径
    QStringList args = {
        "--headless",
        "--convert-to", "pdf",
        "--outdir", pdfOutputDir,
        docxPath
    };
    process.start(libreOfficeCmd, args);
    process.waitForFinished();
    return process.exitStatus() == QProcess::NormalExit;
}
</code ></pre> 
         <hr> 
         <h4>3. 使用示例</h4> 
         <pre><code  style="height: 50vh;" class="hljs">void generateReport() {
    QMap&lt;QString, QString&gt; data {
        {"DeviceName", "Device_123"},
        {"ProgramTimes", "1024"},
        {"ErrorCount", "7"}
    };

    QString templatePath = "template.docx";
    QString outputDocx = "report.docx";
    QString outputPdf = "report.pdf";

    if (replaceTextInDocx(templatePath, outputDocx, data)) {
        qDebug() &lt;&lt; "Docx created.";
        convertDocxToPdf(outputDocx, QFileInfo(outputPdf).absolutePath());
    } else {
        qWarning() &lt;&lt; "Failed to generate report.";
    }
}
</code ></pre> 
         <hr> 
         <h3>⚙️ 平台适配建议</h3> 
         <table>
          <thead>
           <tr>
            <th>平台</th>
            <th>解压命令</th>
            <th>打包命令</th>
            <th>LibreOffice 路径</th>
           </tr>
          </thead>
          <tbody>
           <tr>
            <td>Windows</td>
            <td>可用 PowerShell 或 7-Zip/WinRAR</td>
            <td>使用 QuaZip 或 <code>zip.exe</code ></td>
            <td><code>C:/Program Files/LibreOffice/program/soffice.exe</code ></td>
           </tr>
           <tr>
            <td>Linux/macOS</td>
            <td>系统自带 unzip/zip</td>
            <td>✅</td>
            <td><code>libreoffice</code >（需安装）</td>
           </tr>
          </tbody>
         </table> 
         <hr> 
         <h3>🔐 替代 Zip 的方式（推荐 QuaZip）</h3> 
         <p>使用 <a href="https://github.com/stachenov/quazip" title="QuaZip">QuaZip</a> 可避免系统依赖，用 Qt 风格解压 <code>.docx</code > 和修改文件。</p> 
         <hr> 
         <h3>🧠 进阶优化建议</h3> 
         <ul>
          <li> <p>替换字段时，可支持 <strong>富文本</strong>（如颜色、粗体），参考 <code>w:r</code > 结构合并 XML</p> </li>
          <li> <p>可支持表格、循环字段（遍历表格插入数据）</p> </li>
          <li> <p>添加日志或进度条提示生成过程</p> </li>
         </ul> 
         <h3>✅ 简单占位符替换：适合固定位置的数据</h3> 
         <p>像 <code>${DeviceName}</code >、<code>${ErrorCount}</code > 这种替换，只适用于正文中<strong>已有的固定位置</strong>。比如报告页眉、页脚、标题这些内容。</p> 
         <hr> 
         <h3>❗那如果是表格呢？比如：</h3> 
         <p>你有一个 Word 表格模板是这样的：</p> 
         <table>
          <thead>
           <tr>
            <th>序号</th>
            <th>设备名称</th>
            <th>编程次数</th>
            <th>错误数</th>
           </tr>
          </thead>
          <tbody>
           <tr>
            <td>${1}</td>
            <td>${Device1}</td>
            <td>${Prog1}</td>
            <td>${Err1}</td>
           </tr>
           <tr>
            <td>${2}</td>
            <td>${Device2}</td>
            <td>${Prog2}</td>
            <td>${Err2}</td>
           </tr>
           <tr>
            <td>……</td>
            <td>……</td>
            <td>……</td>
            <td>……</td>
           </tr>
          </tbody>
         </table> 
         <p>这就 <strong>不适合用固定 <code>${}</code > 占位符</strong> 了，因为你无法预知有多少行，也不可能写死 256 行的 <code>${}</code > 占位。</p> 
         <hr> 
         <h3>✅ 推荐方案：<strong>模板中只放一行占位符</strong>，在代码里动态复制表格行（推荐）</h3> 
         <h4>操作流程：</h4> 
         <ol>
          <li> <p>在 Word 中插入一个表格（比如 4 列），写一行示例数据：</p> <pre><code class="hljs">${Index} | ${DeviceName} | ${ProgramTimes} | ${ErrorCount}
</code ></pre> </li>
          <li> <p>在代码里找到这段表格所在的 XML，然后：</p> 
           <ul>
            <li> <p>复制这一整行（<code>&lt;w:tr&gt;</code > 标签）</p> </li>
            <li> <p>替换占位符</p> </li>
            <li> <p>重复插入你需要的行数</p> </li>
           </ul> </li>
         </ol> 
         <hr> 
         <h4>👇 表格 XML 示例（简化后的）：</h4> 
         <pre><code class="hljs">&lt;w:tbl&gt;
  &lt;w:tr&gt;
    &lt;w:tc&gt;&lt;w:p&gt;&lt;w:r&gt;&lt;w:t&gt;${Index}&lt;/w:t&gt;&lt;/w:r&gt;&lt;/w:p&gt;&lt;/w:tc&gt;
    &lt;w:tc&gt;&lt;w:p&gt;&lt;w:r&gt;&lt;w:t&gt;${DeviceName}&lt;/w:t&gt;&lt;/w:r&gt;&lt;/w:p&gt;&lt;/w:tc&gt;
    ...
  &lt;/w:tr&gt;
&lt;/w:tbl&gt;
</code ></pre> 
         <p>只需要：</p> 
         <ul>
          <li> <p>在 XML 中找到 <code>&lt;w:tbl&gt;</code > 中的第一行 <code>&lt;w:tr&gt;</code ></p> </li>
          <li> <p>在代码里复制这个 <code>&lt;w:tr&gt;</code > 节点 N 次，逐个替换 <code>${}</code > 占位符</p> </li>
          <li> <p>替换完后把它们插入 <code>&lt;w:tbl&gt;</code > 中</p> </li>
         </ul> 
         <hr> 
         <h4>✅ Qt C++ 简化示意代码：</h4> 
         <pre><code  style="height: 50vh;" class="hljs">QDomNodeList rows = tableElement.elementsByTagName("w:tr");
QDomNode templateRow = rows.at(1);  // 假设第2行是占位行

for (int i = 0; i &lt; dataList.size(); ++i) {
    QDomNode newRow = templateRow.cloneNode(true);
    QString xml = newRow.toElement().text();
    xml.replace("${Index}", QString::number(i+1));
    xml.replace("${DeviceName}", dataList[i].name);
    xml.replace("${ProgramTimes}", QString::number(dataList[i].prog));
    xml.replace("${ErrorCount}", QString::number(dataList[i].err));
    // 将 newRow 插入到 table 中
    tableElement.appendChild(newRow);
}

// 删除原始模板行（避免留下占位）
tableElement.removeChild(templateRow);
</code ></pre> 
         <blockquote> 
          <p>完整版本会更复杂一点，需要对 <code>w:t</code > 节点内文字进行处理，但原理就是这样。</p> 
         </blockquote> 
         <p>怎么找到这些标签，以及如何定位到你 Word 模板中“哪一行”对应的 XML 标签。</p> 
         <hr> 
         <h3>🧠 背景知识：<code>.docx</code > = ZIP 压缩包 + XML 文件</h3> 
         <p><code>.docx</code > 文件其实是 ZIP 压缩文件，里面的正文存在 <code>word/document.xml</code > 文件里。</p> 
         <h4>表格结构（简化）：</h4> 
         <pre><code class="hljs">&lt;w:tbl&gt;            ← 表格开始
  &lt;w:tr&gt;           ← 表格的一行（Table Row）
    &lt;w:tc&gt;         ← 单元格（Table Cell）
      &lt;w:p&gt;&lt;w:r&gt;&lt;w:t&gt;内容&lt;/w:t&gt;&lt;/w:r&gt;&lt;/w:p&gt;
    &lt;/w:tc&gt;
    ...
  &lt;/w:tr&gt;
  &lt;w:tr&gt;...        ← 第二行
  &lt;/w:tr&gt;
&lt;/w:tbl&gt;
</code ></pre> 
         <ul>
          <li> <p><code>&lt;w:tbl&gt;</code > 表示整个表格。</p> </li>
          <li> <p><code>&lt;w:tr&gt;</code > 表示表格的一行（table row）。</p> </li>
          <li> <p><code>&lt;w:tc&gt;</code > 是表格的一个单元格（table cell）。</p> </li>
          <li> <p><code>&lt;w:t&gt;</code > 是里面的文本内容。</p> </li>
         </ul> 
         <hr> 
         <h3>🔍 如何确认某行在 XML 中长什么样？</h3> 
         <h4>✅ 方法 1：手动解压 + 用文本工具查找</h4> 
         <ol>
          <li> <p>将 Word 模板（<code>.docx</code >）改名为 <code>.zip</code >，例如：</p> <pre><code class="hljs">template.docx → template.zip
</code ></pre> </li>
          <li> <p>解压这个 zip 文件，找到这个路径（arduino）：</p> <pre><code class="hljs">word/document.xml
</code ></pre> </li>
          <li> <p>用 VSCode、Notepad++ 或任何文本编辑器打开它。</p> </li>
          <li> <p>在文件里 <strong>搜索你写在 Word 里的文字</strong>，比如你模板里写了（bash）：</p> <pre><code class="hljs">${DeviceName}
</code ></pre> <p>那你就搜 <code>${DeviceName}</code >，你会看到类似（xml）：</p> <pre><code class="hljs">&lt;w:tr&gt;
  &lt;w:tc&gt;&lt;w:p&gt;&lt;w:r&gt;&lt;w:t&gt;${DeviceName}&lt;/w:t&gt;&lt;/w:r&gt;&lt;/w:p&gt;&lt;/w:tc&gt;
  ...
&lt;/w:tr&gt;
</code ></pre> <p>这整段 <code>&lt;w:tr&gt;...&lt;/w:tr&gt;</code > 就是你想复制的一整行！</p> </li>
         </ol> 
         <hr> 
         <h4>✅ 方法 2：用浏览器格式化 <code>document.xml</code ></h4> 
         <p>你也可以把 <code>document.xml</code > 拖进 Chrome/Edge 浏览器中，它会自动格式化为可读的 XML 树。</p> 
         <hr> 
         <h4>✅ 方法 3：写程序里用 DOM 查找</h4> 
         <p>Qt 也可以自动找到这个结构：</p> 
         <pre><code class="hljs">QDomNodeList tables = doc.elementsByTagName("w:tbl");
QDomElement table = tables.at(0).toElement(); // 假设第一个表格

QDomNodeList rows = table.elementsByTagName("w:tr");
for (int i = 0; i &lt; rows.size(); ++i) {
    QDomElement row = rows.at(i).toElement();
    if (row.text().contains("${DeviceName}")) {
        qDebug() &lt;&lt; "找到了模板行在第" &lt;&lt; i &lt;&lt; "行";
    }
}
</code ></pre> 
         <hr> 
         <h3>📌 小技巧</h3> 
         <ul>
          <li> <p><code>&lt;w:tr&gt;</code > 表示表格的 <strong>一整行</strong>（你需要复制这一整段）。</p> </li>
          <li> <p><code>&lt;w:tc&gt;</code > 表示每个单元格。</p> </li>
          <li> <p><code>&lt;w:t&gt;</code > 是最终的文本内容，你的 <code>${}</code > 占位符一定出现在 <code>&lt;w:t&gt;</code > 标签中。</p> </li>
         </ul> 
         <hr> 
         <h3>✅ 举个真实例子（你 Word 里写了一行）</h3> 
         <p>| ${Index} | ${DeviceName} | ${ProgramTimes} | ${ErrorCount} |</p> 
         <p>它在 <code>document.xml</code > 中就会像这样：</p> 
         <pre><code class="hljs">&lt;w:tr&gt;
  &lt;w:tc&gt;&lt;w:p&gt;&lt;w:r&gt;&lt;w:t&gt;${Index}&lt;/w:t&gt;&lt;/w:r&gt;&lt;/w:p&gt;&lt;/w:tc&gt;
  &lt;w:tc&gt;&lt;w:p&gt;&lt;w:r&gt;&lt;w:t&gt;${DeviceName}&lt;/w:t&gt;&lt;/w:r&gt;&lt;/w:p&gt;&lt;/w:tc&gt;
  &lt;w:tc&gt;&lt;w:p&gt;&lt;w:r&gt;&lt;w:t&gt;${ProgramTimes}&lt;/w:t&gt;&lt;/w:r&gt;&lt;/w:p&gt;&lt;/w:tc&gt;
  &lt;w:tc&gt;&lt;w:p&gt;&lt;w:r&gt;&lt;w:t&gt;${ErrorCount}&lt;/w:t&gt;&lt;/w:r&gt;&lt;/w:p&gt;&lt;/w:tc&gt;
&lt;/w:tr&gt;
</code ></pre> 
         <p>你只要找到这一段，然后用 DOM 克隆这个 <code>&lt;w:tr&gt;</code > 元素，替换 <code>${}</code > 就完成了动态行插入！</p> 
         <p>&nbsp;</p> 
         <h3>🎯 目标功能</h3> 
         <p>从一个 Word 模板（<code>.docx</code >）中读取表格模板行，根据数据动态插入多行内容，然后重新打包生成一个新的 Word 报告文件。</p> 
         <hr> 
         <h3>📄 示例数据格式</h3> 
         <p>我们将生成如下表格内容：</p> 
         <table>
          <thead>
           <tr>
            <th>序号</th>
            <th>设备名称</th>
            <th>编程次数</th>
            <th>错误数</th>
           </tr>
          </thead>
          <tbody>
           <tr>
            <td>1</td>
            <td>DevA</td>
            <td>123</td>
            <td>0</td>
           </tr>
           <tr>
            <td>2</td>
            <td>DevB</td>
            <td>456</td>
            <td>1</td>
           </tr>
           <tr>
            <td>3</td>
            <td>DevC</td>
            <td>789</td>
            <td>2</td>
           </tr>
          </tbody>
         </table> 
         <hr> 
         <h3>📦 示例项目结构（bash）</h3> 
         <pre><code class="hljs">DynamicWordReport/
├── template.docx         ← 你准备的 Word 模板（只包含一行表格占位符）
├── main.cpp              ← 主代码
├── wordgen.pro           ← Qt 工程文件
</code ></pre> 
         <hr> 
         <h3>📄 Word 模板说明（template.docx）</h3> 
         <p>在 Word 中创建一个表格：</p> 
         <p>| ${Index} | ${DeviceName} | ${ProgramTimes} | ${ErrorCount} |</p> 
         <p>保存为 <code>template.docx</code >，用作模板。只需要这一行，后续会被程序克隆插入。</p> 
         <hr> 
         <h3>✅ 示例代码：main.cpp</h3> 
         <pre><code  style="height: 50vh;" class="hljs">#include &lt;QCoreApplication&gt;
#include &lt;QDomDocument&gt;
#include &lt;QFile&gt;
#include &lt;QProcess&gt;
#include &lt;QTemporaryDir&gt;
#include &lt;QTextStream&gt;
#include &lt;QDebug&gt;

struct DeviceData {
    QString name;
    int programTimes;
    int errorCount;
};

bool generateReport(const QString&amp; templatePath, const QString&amp; outputPath, const QList&lt;DeviceData&gt;&amp; dataList) {
    QTemporaryDir tempDir;
    if (!tempDir.isValid()) return false;

    QString unzipPath = tempDir.path();
    QProcess::execute("unzip", { templatePath, "-d", unzipPath });

    QString docXmlPath = unzipPath + "/word/document.xml";
    QFile file(docXmlPath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return false;

    QDomDocument doc;
    if (!doc.setContent(&amp;file)) {
        file.close();
        return false;
    }
    file.close();

    QDomNodeList tables = doc.elementsByTagName("w:tbl");
    if (tables.isEmpty()) return false;

    QDomElement table = tables.at(0).toElement();
    QDomNodeList rows = table.elementsByTagName("w:tr");
    if (rows.size() &lt; 2) return false;

    QDomNode templateRow = rows.at(1);  // 占位模板行
    for (int i = 0; i &lt; dataList.size(); ++i) {
        QDomNode newRow = templateRow.cloneNode(true);
        QString rowXml = newRow.toElement().text();

        // 替换文本
        QString xmlString = newRow.toElement().ownerDocument().toString();

        newRow = newRow.toElement();
        QDomNodeList cells = newRow.toElement().elementsByTagName("w:t");
        for (int j = 0; j &lt; cells.count(); ++j) {
            QDomElement cell = cells.at(j).toElement();
            QString text = cell.text();
            text.replace("${Index}", QString::number(i + 1));
            text.replace("${DeviceName}", dataList[i].name);
            text.replace("${ProgramTimes}", QString::number(dataList[i].programTimes));
            text.replace("${ErrorCount}", QString::number(dataList[i].errorCount));
            cell.firstChild().setNodeValue(text);
        }

        table.appendChild(newRow);
    }

    table.removeChild(templateRow); // 删除原始模板行

    // 保存 document.xml
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) return false;
    QTextStream out(&amp;file);
    doc.save(out, 2);
    file.close();

    // 打包回 .docx
    QString cwd = QDir::currentPath();
    QDir::setCurrent(unzipPath);
    QProcess::execute("zip", { "-r", outputPath, "." });
    QDir::setCurrent(cwd);

    return true;
}

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QList&lt;DeviceData&gt; dataList = {
        {"DevA", 123, 0},
        {"DevB", 456, 1},
        {"DevC", 789, 2}
    };

    QString templatePath = "template.docx";
    QString outputPath = "report.docx";

    if (generateReport(templatePath, outputPath, dataList)) {
        qDebug() &lt;&lt; "报告生成成功：" &lt;&lt; outputPath;
    } else {
        qDebug() &lt;&lt; "生成失败！";
    }

    return 0;
}
</code ></pre> 
         <hr> 
         <h3>🔧 Qt 工程文件（wordgen.pro）</h3> 
         <pre><code class="hljs">QT += core xml
CONFIG += console
CONFIG -= app_bundle
TARGET = wordgen
TEMPLATE = app

SOURCES += main.cpp
</code ></pre> 
         <hr> 
         <h3>✅ 运行要求</h3> 
         <ul>
          <li> <p>需要安装 <code>unzip</code > 和 <code>zip</code > 命令（大部分 Linux/macOS 默认有，Windows 可用 7-Zip 或添加 zip.exe）。</p> </li>
          <li> <p>需要将模板 <code>template.docx</code > 放在工程目录下。</p> </li>
          <li> <p>编译并运行，会生成 <code>report.docx</code >，可以用 Word 打开。</p> </li>
         </ul> 
         <p>&nbsp;</p> 
         <h3>🎯 目标</h3> 
         <p>在 Windows 平台上，使用 Qt 和 QuaZip 库解压缩 <code>.docx</code > 模板文件，编辑其中的 <code>document.xml</code >，动态插入表格行数据，然后重新压缩生成新的 <code>.docx</code > 文件。</p> 
         <hr> 
         <h3>🛠️ 步骤概览</h3> 
         <ol>
          <li> <p><strong>准备工作</strong>：下载并编译 <code>zlib</code > 和 <code>QuaZip</code > 库。</p> </li>
          <li> <p><strong>配置 Qt 项目</strong>：将 <code>zlib</code > 和 <code>QuaZip</code > 集成到 Qt 项目中。</p> </li>
          <li> <p><strong>实现功能</strong>：编写代码实现 <code>.docx</code > 文件的解压缩、编辑和重新压缩。</p> </li>
         </ol> 
         <hr> 
         <h3>1. 准备工作</h3> 
         <h4>1.1 下载并编译 <code>zlib</code > 库</h4> 
         <p><code>.docx</code > 文件本质上是一个 ZIP 压缩包，<code>QuaZip</code > 库依赖 <code>zlib</code > 来处理 ZIP 文件。因此，需要先获取并编译 <code>zlib</code >。</p> 
         <ul>
          <li> <p><strong>下载 <code>zlib</code > 源码</strong>：从 <a href="http://www.zlib.net/" title="zlib 官方网站" rel="nofollow">zlib 官方网站</a> 下载最新版本的源码。</p> </li>
          <li> <p><strong>编译 <code>zlib</code ></strong>：</p> 
           <ol>
            <li> <p>解压下载的 <code>zlib</code > 源码包。</p> </li>
            <li> <p>使用 Visual Studio 的开发者命令提示符，导航到 <code>zlib</code > 源码目录。</p> </li>
            <li> <p>执行以下命令生成 <code>Makefile（cmd）</code >：</p> </li>
           </ol> </li>
         </ul> 
         <pre><code class="hljs">nmake -f win32/Makefile.msc
</code ></pre> 
         <p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 4.编译生成 <code>zlib1.dll</code > 和对应的库文件。<br> &nbsp;<strong>注意</strong>：详细的编译步骤和可能遇到的问题，可参考 Qt基于QuaZIP实现文件压缩/解压（Win下）。</p> 
         <h4>1.2 下载并编译 <code>QuaZip</code > 库</h4> 
         <ul>
          <li> <p><strong>下载 <code>QuaZip</code > 源码</strong>：从 <a href="https://github.com/stachenov/quazip" title="QuaZip 官方 GitHub 仓库">QuaZip 官方 GitHub 仓库</a> 获取最新源码。</p> </li>
          <li> <p><strong>编译 <code>QuaZip</code ></strong>：</p> 
           <ol>
            <li> <p>解压 <code>QuaZip</code > 源码包。</p> </li>
            <li> <p>在 <code>QuaZip</code > 源码目录中创建 <code>include</code > 和 <code>lib</code > 文件夹。</p> </li>
            <li> <p>将之前编译的 <code>zlib</code > 的头文件（如 <code>zlib.h</code >、<code>zconf.h</code >）复制到 <code>include</code > 文件夹，将 <code>zlib</code > 的库文件（如 <code>zlib1.lib</code >、<code>zlib1.dll</code >）复制到 <code>lib</code > 文件夹。</p> </li>
            <li> <p>使用 Qt Creator 打开 <code>quazip.pro</code > 工程文件。</p> </li>
            <li> <p>在 <code>quazip.pro</code > 中添加对 <code>zlib</code > 的依赖：</p> <pre><code class="hljs">INCLUDEPATH += $$PWD/include
LIBS += -L$$PWD/lib -lzlib1
</code ></pre> </li>
            <li> <p>配置项目为合适的构建模式（如 Release 或 Debug），然后编译生成 <code>quazip.dll</code > 和对应的库文件。</p> </li>
           </ol> 
           <blockquote> 
            <p><strong>提示</strong>：在编译 <code>QuaZip</code > 时，确保 <code>zlib</code > 的库和头文件路径正确设置。更多细节可参考 Qt基于QuaZIP在Win下实现文件的压缩/解压。</p> 
           </blockquote> </li>
         </ul> 
         <hr> 
         <h3>2. 配置 Qt 项目</h3> 
         <p>在你的 Qt 项目中，需要链接 <code>zlib</code > 和 <code>QuaZip</code > 库，并包含相应的头文件。</p> 
         <ul>
          <li> <p><strong>在 <code>.pro</code > 文件中添加以下内容</strong>：</p> <pre><code class="hljs">QT += core xml
CONFIG += console
CONFIG -= app_bundle

# QuaZip 和 zlib 的包含路径
INCLUDEPATH += path/to/quazip/include
INCLUDEPATH += path/to/zlib/include

# QuaZip 和 zlib 的库路径
LIBS += -Lpath/to/quazip/lib -lquazip
LIBS += -Lpath/to/zlib/lib -lzlib1
</code ></pre> 
           <blockquote> 
            <p><strong>注意</strong>：将 <code>path/to/quazip/include</code >、<code>path/to/zlib/include</code >、<code>path/to/quazip/lib</code > 和 <code>path/to/zlib/lib</code > 替换为实际的路径。</p> 
           </blockquote> </li>
          <li> <p><strong>确保在可执行文件目录下包含必要的 DLL 文件</strong>：</p> <p>将 <code>zlib1.dll</code > 和 <code>quazip.dll</code > 复制到可执行文件所在的目录，确保程序在运行时能够找到这些动态链接库。</p> </li>
         </ul> 
         <hr> 
         <h3>3. 实现功能</h3> 
         <p>以下是使用 <code>QuaZip</code > 库解压缩 <code>.docx</code > 文件、编辑 <code>document.xml</code > 并重新压缩的示例代码：</p> 
         <pre><code  style="height: 50vh;" class="hljs">#include &lt;QCoreApplication&gt;
#include &lt;QFile&gt;
#include &lt;QDebug&gt;
#include &lt;QDomDocument&gt;
#include &lt;JlCompress.h&gt;

struct DeviceData {
    QString name;
    int programTimes;
    int errorCount;
};

bool generateReport(const QString&amp; templatePath, const QString&amp; outputPath, const QList&lt;DeviceData&gt;&amp; dataList) {
    // 1. 解压缩模板文件
    QString tempDir = QDir::tempPath() + "/docx_temp/";
    if (!JlCompress::extractDir(templatePath, tempDir).isEmpty()) {
        qDebug() &lt;&lt; "解压成功";
    } else {
        qDebug() &lt;&lt; "解压失败";
        return false;
    }

    // 2. 加载 document.xml
    QString docXmlPath = tempDir + "word/document.xml";
    QFile file(docXmlPath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() &lt;&lt; "无法打开 document.xml";
        return false;
    }

    QDomDocument doc;
    if (!doc.setContent(&amp;file)) {
        file.close();
        qDebug() &lt;&lt; "解析 document.xml 失败";
        return false;
    }
    file.close();

    // 3. 查找表格并插入数据
    QDomNodeList tables = doc.elementsByTagName("w:tbl");
    if (tables.isEmpty()) {
        qDebug() &lt;&lt; "未找到表格";
        return false;
    }

    QDomElement table = tables.at(0).toElement();
    QDomNodeList rows = table.elementsByTagName("w:tr");
    if (rows.size() &lt; 2) {
        qDebug() &lt;&lt; "表格行数不足";
        return false;
    }

    QDomNode templateRow = rows.at(1);  // 假设第二行是模板行
    for (int i = 0; i &lt; dataList.size(); ++i) {
        QDomNode newRow = templateRow.cloneNode(true);
        QDomNodeList cells = newRow.toElement().elementsByTagName("
::contentReference[oaicite:0]{index=0}
 
</code ></pre> 
         <h3>🧭 操作步骤详解：使用 Visual Studio 开发者命令提示符编译 zlib</h3> 
         <h4>✅ 1. 安装 Visual Studio（如未安装）</h4> 
         <p>如果你已经安装 Visual Studio，请跳过这一步。确保安装时勾选了 <strong>C++开发工具集</strong>。</p> 
         <hr> 
         <h4>✅ 2. 打开 “x64 Native Tools Command Prompt for VS XXXX”</h4> 
         <p>这个是 Visual Studio 安装时自动添加的命令提示符工具。打开方式如下：</p> 
         <ul>
          <li> <p><strong>开始菜单</strong> → 输入 <code>x64 Native Tools Command Prompt for VS 2022</code >（或你安装的版本）</p> </li>
          <li> <p>找到后 <strong>右键“以管理员身份运行”</strong></p> </li>
         </ul> 
         <blockquote> 
          <p>⚠️ 你也可以用 <code>x86 Native Tools</code >，但建议根据你的目标平台选择。</p> 
         </blockquote> 
         <hr> 
         <h4>✅ 3. 下载并解压 <code>zlib</code > 源码</h4> 
         <ul>
          <li> <p>访问官网：<a href="https://zlib.net" title="zlib Home Site" rel="nofollow">zlib Home Site</a></p> </li>
          <li> <p>下载如 <code>zlib-1.2.13.zip</code ></p> </li>
          <li> <p>解压到一个路径，如：<br> <code>C:\Dev\zlib-1.2.13\</code ></p> </li>
         </ul> 
         <hr> 
         <h4>✅ 4. 切换到解压目录</h4> 
         <p>在刚才打开的命令提示符窗口中，执行以下命令：</p> 
         <pre><code class="hljs">cd /d C:\Dev\zlib-1.2.13
</code ></pre> 
         <p>cmd</p> 
         <p>复制编辑</p> 
         <p><code>cd /d C:\Dev\zlib-1.2.13 </code ></p> 
         <p>解释：</p> 
         <ul>
          <li> <p><code>cd /d</code >：切换磁盘和目录（Windows CMD 特有）</p> </li>
          <li> <p><code>C:\Dev\zlib-1.2.13</code >：是你解压的 zlib 路径</p> </li>
         </ul> 
         <hr> 
         <h4>✅ 5. 编译 zlib 使用官方 Makefile</h4> 
         <p>执行以下命令：</p> 
         <pre><code class="hljs">nmake -f win32\Makefile.msc

</code ></pre> 
         <p>这会使用微软提供的 <code>nmake</code > 工具，调用 zlib 自带的 <code>Makefile.msc</code > 文件进行构建。</p> 
         <hr> 
         <h4>💡 成功后会生成这些文件：</h4> 
         <table>
          <thead>
           <tr>
            <th>文件名</th>
            <th>说明</th>
           </tr>
          </thead>
          <tbody>
           <tr>
            <td><code>zlib1.dll</code ></td>
            <td>动态链接库</td>
           </tr>
           <tr>
            <td><code>zlib.lib</code ></td>
            <td>对应的导入库（用于链接）</td>
           </tr>
           <tr>
            <td><code>zlib1.pdb</code ></td>
            <td>调试信息</td>
           </tr>
           <tr>
            <td><code>zlib.h</code ></td>
            <td>头文件</td>
           </tr>
           <tr>
            <td><code>zconf.h</code ></td>
            <td>配套头文件</td>
           </tr>
          </tbody>
         </table> 
         <p>这些文件之后会用于构建 QuaZip 或链接到你的 Qt 项目。</p> 
         <hr> 
         <h4>❗ 若出现错误：</h4> 
         <ul>
          <li> <p>确保用的是 <strong>Visual Studio 的命令提示符</strong>（而不是普通 CMD）</p> </li>
          <li> <p>确保路径中 <strong>没有空格或中文</strong></p> </li>
          <li> <p>确保你有 <strong>写权限</strong>，最好以管理员身份运行</p> </li>
         </ul> 
         <p>&nbsp;</p> 
         <p>下载的是 QuaZip 的 <a href="https://github.com/stachenov/quazip" title="GitHub 仓库">GitHub 仓库</a> 上的源码包，这个版本默认是 <strong>CMake 构建系统</strong>，而不是老版本使用的 <code>.pro</code > 文件（Qt Project 文件）。</p> 
         <hr> 
         <h3>🧩 问题说明</h3> 
         <p>现代版本的 QuaZip 使用的是 <strong>CMake 构建系统</strong>，所以源码里没有 <code>.pro</code > 文件是正常的。你可以有两种解决方案：</p> 
         <hr> 
         <h3>✅ 方案：继续使用 <strong>CMake 构建 QuaZip</strong></h3> 
         <p>这是官方推荐的做法（更现代、更稳定）。</p> 
         <h4>步骤如下：</h4> 
         <ol>
          <li> <p>解压 GitHub 下载的 <code>quazip</code > 源码包，比如到 <code>C:\Dev\quazip</code ></p> </li>
          <li> <p>在该目录下新建一个构建文件夹，例如（bash）：</p> <pre><code class="hljs">mkdir build
cd build
</code ></pre> </li>
          <li> <p>使用 <strong>Qt 的 CMake 工具链</strong>来生成工程（确保你装了 Qt 的 CMake 支持）（bash）：</p> </li>
         </ol> 
         <pre><code class="hljs">cmake .. -DCMAKE_PREFIX_PATH="C:/Qt/6.5.0/msvc2019_64"
cmake --build . --config Release
</code ></pre> 
         <blockquote> 
          <p>📌 替换 <code>"C:/Qt/6.5.0/msvc2019_64"</code > 为你实际安装 Qt 的路径。</p> 
         </blockquote> 
         <p>构建成功后你会得到：</p> 
         <ul>
          <li> <p><code>quazip.dll</code ></p> </li>
          <li> <p><code>quazip.lib</code ></p> </li>
          <li> <p><code>quazip5.dll</code >（旧版本）</p> </li>
          <li> <p><code>include</code > 头文件路径</p> </li>
         </ul> 
         <p>之后就可以在你的 Qt 项目中使用它了。</p> 
         <h3>🚀 后续操作</h3> 
         <p>不管你选用哪种方式构建：</p> 
         <ul>
          <li> <p>最终你会得到：</p> 
           <ul>
            <li> <p><code>quazip.dll</code ></p> </li>
            <li> <p><code>quazip.lib</code ></p> </li>
            <li> <p>头文件（一般在 <code>quazip/</code > 文件夹下）</p> </li>
           </ul> </li>
          <li> <p>然后在你自己的 Qt 项目中 <code>.pro</code > 文件里配置（pro）：</p> </li>
         </ul> 
         <pre><code class="hljs">INCLUDEPATH += path/to/quazip
LIBS += -Lpath/to/quazip/lib -lquazip
</code ></pre> 
         <p>&nbsp;</p> 
         <h5>重新执行 <code>cmake</code >，并指定 ZLIB 路径(powershell)：</h5> 
         <pre><code class="hljs">cmake .. `
  -DZLIB_LIBRARY="D:/Dev/zlib-1.2.13/zlib.lib" `
  -DZLIB_INCLUDE_DIR="D:/Dev/zlib-1.2.13" `
  -DCMAKE_PREFIX_PATH="D:/Qt/6.6.3/msvc2019_64"
</code ></pre> 
         <p>注意：路径用 <code>/</code > 或 <code>\\</code > 都行，但不能用 <code>\</code >（容易被转义）。</p> 
         <hr> 
         <h3>✅ 构建完成后再执行(powershell)：</h3> 
         <pre><code class="hljs">cmake --build . --config Release
</code ></pre> 
         <h3>✅ 一、解释这三行（powershell）</h3> 
         <pre><code class="hljs">cmake .. `
  -DZLIB_LIBRARY="D:/Dev/zlib-1.2.13/zlib.lib" `
  -DZLIB_INCLUDE_DIR="D:/Dev/zlib-1.2.13" `
  -DCMAKE_PREFIX_PATH="D:/Qt/6.6.3/msvc2019_64"
</code ></pre> 
         <p>等价于这一行完整的命令（powershell）：</p> 
         <pre><code class="hljs">cmake .. -DZLIB_LIBRARY="D:/Dev/zlib-1.2.13/zlib.lib" -DZLIB_INCLUDE_DIR="D:/Dev/zlib-1.2.13" -DCMAKE_PREFIX_PATH="D:/Qt/6.6.3/msvc2019_64"
</code ></pre> 
         <hr> 
         <h3>✅ 二、每个参数什么意思？</h3> 
         <table>
          <thead>
           <tr>
            <th>参数名</th>
            <th>含义</th>
           </tr>
          </thead>
          <tbody>
           <tr>
            <td><code>cmake ..</code ></td>
            <td>进入上一级的 <code>CMakeLists.txt</code > 所在目录，准备生成项目</td>
           </tr>
           <tr>
            <td><code>-DZLIB_LIBRARY=...</code ></td>
            <td>指定 zlib 的 <code>.lib</code > 文件路径</td>
           </tr>
           <tr>
            <td><code>-DZLIB_INCLUDE_DIR=...</code ></td>
            <td>指定 zlib 的头文件所在目录（要有 <code>zlib.h</code >）</td>
           </tr>
           <tr>
            <td><code>-DCMAKE_PREFIX_PATH=...</code ></td>
            <td>指定 Qt 的路径，让 CMake 能找到 Qt6 的模块</td>
           </tr>
          </tbody>
         </table> 
         <hr> 
         <h3>✅ 三、我该怎么执行？</h3> 
         <h4>🔸 如果你在 <strong>PowerShell</strong> 里</h4> 
         <p>可以直接复制我三行格式的那种，回车执行就行(powershell)：</p> 
         <pre><code class="hljs">cmake .. `
  -DZLIB_LIBRARY="D:/Dev/zlib-1.2.13/zlib.lib" `
  -DZLIB_INCLUDE_DIR="D:/Dev/zlib-1.2.13" `
  -DCMAKE_PREFIX_PATH="D:/Qt/6.6.3/msvc2019_64"
</code ></pre> 
         <blockquote> 
          <p><code>注意：反引号（</code >）是键盘左上角那个键，不是单引号（'）！</p> 
         </blockquote> 
         <hr> 
         <h4>🔸 如果你在 <strong>cmd 命令提示符</strong> 或 <strong>写到 <code>.bat</code > 脚本</strong>里</h4> 
         <p>用一行写法（不要反引号）（cmd）：</p> 
         <pre><code class="hljs">cmake .. -DZLIB_LIBRARY="D:/Dev/zlib-1.2.13/zlib.lib" -DZLIB_INCLUDE_DIR="D:/Dev/zlib-1.2.13" -DCMAKE_PREFIX_PATH="D:/Qt/6.6.3/msvc2019_64"
</code ></pre> 
         <p><span style="color:#fe2c24">&nbsp;注意：中途遇到问题可问AI,如：不应该去拉取 <code>bzip2。</code ></span></p> 
         <p>&nbsp;</p> 
         <p>下面是将你提供的报表生成逻辑封装为一个 <code>WordReportGenerator</code > C++ 类的完整 Qt 示例，使用 <strong>QuaZip</strong> 替代了命令行中的 <code>unzip</code > 和 <code>zip</code >，并保持你的原有结构清晰可维护。</p> 
         <h4>✅ 修改亮点</h4> 
         <ul>
          <li> <p>使用 <code>QuaZip</code > 实现 <code>.docx</code > 的解压与打包；</p> </li>
          <li> <p>封装为 <code>WordReportGenerator</code > 类，逻辑职责清晰；</p> </li>
          <li> <p>支持灵活配置模板路径与输出路径；</p> </li>
          <li> <p>完整保留 XML 替换逻辑。</p> </li>
         </ul> 
         <hr> 
         <h4>✅ 最终代码（支持直接使用）</h4> 
         <h5>📄 <code>main.cpp</code ></h5> 
         <pre><code  style="height: 50vh;" class="hljs">#include &lt;QCoreApplication&gt;
#include &lt;QDebug&gt;
#include "wordreportgenerator.h"

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    QList&lt;DeviceData&gt; dataList = {
        {"DevA", 123, 0},
        {"DevB", 456, 1},
        {"DevC", 789, 2}
    };

    WordReportGenerator generator;
    QString templatePath = "libreofficeTest.docx";
    QString outputPath = "report1.docx";

    if (generator.generate(templatePath, outputPath, dataList)) {
        qDebug() &lt;&lt; "报告生成成功：" &lt;&lt; outputPath;
    } else {
        qDebug() &lt;&lt; "报告生成失败！";
    }

    return 0;
}
</code ></pre> 
         <hr> 
         <h5>📄 <code>wordreportgenerator.h</code ></h5> 
         <pre><code  style="height: 50vh;" class="hljs">#pragma once

#include &lt;QString&gt;
#include &lt;QList&gt;

struct DeviceData {
    QString name;
    int programTimes;
    int errorCount;
};

class WordReportGenerator {
public:
    bool generate(const QString &amp;templatePath, const QString &amp;outputPath, const QList&lt;DeviceData&gt; &amp;dataList);
};
</code ></pre> 
         <hr> 
         <h5>📄 <code>wordreportgenerator.cpp</code ></h5> 
         <pre><code  style="height: 50vh;" class="hljs">#include "wordreportgenerator.h"
#include &lt;QTemporaryDir&gt;
#include &lt;QFile&gt;
#include &lt;QDir&gt;
#include &lt;QDomDocument&gt;
#include &lt;QTextStream&gt;
#include &lt;JlCompress.h&gt;

bool WordReportGenerator::generate(const QString &amp;templatePath, const QString &amp;outputPath, const QList&lt;DeviceData&gt; &amp;dataList) {
    QTemporaryDir tempDir;
    if (!tempDir.isValid()) return false;

    QString unzipPath = tempDir.path();

    // 解压 docx 到临时目录
    if (!JlCompress::extractDir(templatePath, unzipPath)) {
        return false;
    }

    QString docXmlPath = unzipPath + "/word/document.xml";
    QFile file(docXmlPath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) return false;

    QDomDocument doc;
    if (!doc.setContent(&amp;file)) {
        file.close();
        return false;
    }
    file.close();

    QDomNodeList tables = doc.elementsByTagName("w:tbl");
    if (tables.isEmpty()) return false;

    QDomElement table = tables.at(0).toElement();
    QDomNodeList rows = table.elementsByTagName("w:tr");
    if (rows.size() &lt; 2) return false;

    QDomNode templateRow = rows.at(1); // 占位模板行

    for (int i = 0; i &lt; dataList.size(); ++i) {
        QDomNode newRow = templateRow.cloneNode(true);
        QDomNodeList cells = newRow.toElement().elementsByTagName("w:t");

        for (int j = 0; j &lt; cells.count(); ++j) {
            QDomElement cell = cells.at(j).toElement();
            QString text = cell.text();
            text.replace("${Index}", QString::number(i + 1));
            text.replace("${DeviceName}", dataList[i].name);
            text.replace("${ProgramTimes}", QString::number(dataList[i].programTimes));
            text.replace("${ErrorCount}", QString::number(dataList[i].errorCount));
            cell.firstChild().setNodeValue(text);
        }

        table.appendChild(newRow);
    }

    table.removeChild(templateRow); // 删除原始模板行

    // 保存修改后的 XML
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) return false;
    QTextStream out(&amp;file);
    doc.save(out, 2);
    file.close();

    // 压缩为 .docx
    if (QFile::exists(outputPath)) {
        QFile::remove(outputPath);
    }

    QStringList files = QDir(unzipPath).entryList(QDir::NoDotAndDotDot | QDir::Dirs | QDir::Files, QDir::Name);
    bool success = JlCompress::compressDir(outputPath, unzipPath);
    return success;
}
</code ></pre> 
         <h3>🔧 要求</h3> 
         <p>确保你项目里：</p> 
         <ul>
          <li> <p>已正确链接 <strong>QuaZip</strong></p> </li>
          <li> <p>已包含 QuaZip 的头文件</p> </li>
          <li> <p>具备 zlib 库（你之前已经搞定 ✅）</p> </li>
         </ul> 
        </div> 
       </div> 
      </article>  
     </div> 
     <div class="directory-boxshadow-dialog" style="display:none;"> 
      <div class="directory-boxshadow-dialog-box"> 
      </div> 
      <div class="vip-limited-time-offer-box-new" id="vip-limited-time-offer-box-new"> 
       <img class="limited-img limited-img-new" src="https://csdnimg.cn/release/blogv2/dist/pc/img/vip-limited-close-newWhite.png"> 
       <div class="vip-limited-time-top">
         确定要放弃本次机会？ 
       </div> 
       <span class="vip-limited-time-text">福利倒计时</span> 
       <div class="limited-time-box-new"> 
        <span class="time-hour"></span> 
        <i>:</i> 
        <span class="time-minite"></span> 
        <i>:</i> 
        <span class="time-second"></span> 
       </div> 
       <div class="limited-time-vip-box"> 
        <p> <img class="coupon-img" src="https://csdnimg.cn/release/blogv2/dist/pc/img/vip-limited-close-roup.png"> <span class="def">立减 ¥</span> <span class="active limited-num"></span> </p> 
        <span class="">普通VIP年卡可用</span> 
       </div> 
       <a class="limited-time-btn-new" href="https://mall.csdn.net/vip" data-report-click="{&quot;spm&quot;:&quot;1001.2101.3001.9621&quot;}" data-report-query="spm=1001.2101.3001.9621">立即使用</a> 
      </div> 
     </div> 
     <div class="more-toolbox-new more-toolbar" id="toolBarBox"> 
      <div class="left-toolbox"> 
       <div class="toolbox-left"> 
        <div class="profile-box"> 
         <a class="profile-href" target="_blank" href="https://blog.csdn.net/m0_60608144"><img class="profile-img" src="https://profile-avatar.csdnimg.cn/97252ba03f3f4106b2948a9eb6a901b6_m0_60608144.jpg!1"> <span class="profile-name"> 终不似JHH </span> </a> 
        </div> 
        <div class="profile-attend"> 
         <a class="tool-attend tool-bt-button tool-bt-attend" href="javascript:;" data-report-view="{&quot;mod&quot;:&quot;1592215036_002&quot;,&quot;spm&quot;:&quot;1001.2101.3001.4232&quot;,&quot;extend1&quot;:&quot;已关注&quot;}">已关注</a> 
         <a class="tool-item-follow active-animation" style="display:none;">已关注</a> 
        </div> 
       </div> 
       <div class="toolbox-middle"> 
        <ul class="toolbox-list"> 
         <li class="tool-item tool-item-size tool-active is-like" id="is-like" data-type="bottom"> <a class="tool-item-href"> <img style="display:none;" id="is-like-imgactive-animation-like" class="animation-dom active-animation" src="https://csdnimg.cn/release/blogv2/dist/pc/img/tobarThumbUpactive.png" alt=""> <img class="isactive" style="display:none" id="is-like-imgactive" src="https://csdnimg.cn/release/blogv2/dist/pc/img/toolbar/like-active.png" alt=""> <img class="isdefault" style="display:block" id="is-like-img" src="https://csdnimg.cn/release/blogv2/dist/pc/img/toolbar/like.png" alt=""> <span id="spanCount" class="count "> 19 </span> </a> 
          <div class="tool-hover-tip">
           <span class="text space">点赞</span>
          </div> </li> 
         <li class="tool-item tool-item-size tool-active is-unlike" id="is-unlike"> <a class="tool-item-href"> <img class="isactive" style="margin-right:0px;display:none" id="is-unlike-imgactive" src="https://csdnimg.cn/release/blogv2/dist/pc/img/toolbar/unlike-active.png" alt=""> <img class="isdefault" style="margin-right:0px;display:block" id="is-unlike-img" src="https://csdnimg.cn/release/blogv2/dist/pc/img/toolbar/unlike.png" alt=""> <span id="unlikeCount" class="count "></span> </a> 
          <div class="tool-hover-tip">
           <span class="text space">踩</span>
          </div> </li> 
         <li class="tool-item tool-item-size tool-active is-collection "> <a class="tool-item-href" href="javascript:;" data-report-click="{&quot;mod&quot;:&quot;popu_824&quot;,&quot;spm&quot;:&quot;1001.2101.3001.4130&quot;,&quot;ab&quot;:&quot;new&quot;}"> <img style="display:none" id="is-collection-img-collection" class="animation-dom active-animation" src="https://csdnimg.cn/release/blogv2/dist/pc/img/toolbar/collect-active.png" alt=""> <img class="isdefault" id="is-collection-img" style="display:block" src="https://csdnimg.cn/release/blogv2/dist/pc/img/toolbar/collect.png" alt=""> <img class="isactive" id="is-collection-imgactive" style="display:none" src="https://csdnimg.cn/release/blogv2/dist/pc/img/newCollectActive.png" alt=""> <span class="count get-collection " data-num="19" id="get-collection"> 19 </span> </a> 
          <div class="tool-hover-tip collect"> 
           <div class="collect-operate-box"> 
            <span class="collect-text" id="is-collection"> 收藏 </span> 
           </div> 
          </div> 
          <div class="tool-active-list"> 
           <div class="text">
             觉得还不错? 
            <span class="collect-text" id="tool-active-list-collection"> 一键收藏 </span> 
            <img id="tool-active-list-close" src="https://csdnimg.cn/release/blogv2/dist/pc/img/collectionCloseWhite.png" alt=""> 
           </div> 
          </div> </li> 
         <li class="tool-item tool-item-size tool-active tool-item-comment"> 
          <div class="guide-rr-first"> 
           <img src="https://csdnimg.cn/release/blogv2/dist/pc/img/guideRedReward01.png" alt=""> 
           <button class="btn-guide-known">知道了</button> 
          </div> <a class="tool-item-href go-side-comment" data-report-click="{&quot;spm&quot;:&quot;1001.2101.3001.7009&quot;}"> <img class="isdefault" src="https://csdnimg.cn/release/blogv2/dist/pc/img/toolbar/comment.png" alt=""> <span class="count"> 0 </span> </a> 
          <div class="tool-hover-tip">
           <span class="text space">评论</span>
          </div> </li> 
         <li class="tool-item tool-item-size tool-active tool-QRcode" data-type="article" id="tool-share"> <a class="tool-item-href" href="javascript:;" data-report-view="{&quot;spm&quot;:&quot;3001.4129&quot;,&quot;extra&quot;:{&quot;type&quot;:&quot;blogdetail&quot;}}"> <img class="isdefault" src="https://csdnimg.cn/release/blogv2/dist/pc/img/toolbar/share.png" alt=""> <span class="count">分享</span> </a> 
          <div class="QRcode active" id="tool-QRcode"> 
           <div class="share-bg-box"> 
            <div class="share-content"> 
             <a id="copyPosterUrl" data-type="link" class="btn-share">复制链接</a> 
            </div> 
            <div class="share-content"> 
             <a class="btn-share" data-type="qq">分享到 QQ</a> 
            </div> 
            <div class="share-content"> 
             <a class="btn-share" data-type="weibo">分享到新浪微博</a> 
            </div> 
            <div class="share-code"> 
             <div class="share-code-box" id="shareCode"></div> 
             <div class="share-code-text"> 
              <img src="https://csdnimg.cn/release/blogv2/dist/pc/img/share/icon-wechat.png" alt="">扫一扫 
             </div> 
            </div> 
           </div> 
          </div> </li> 
         <li class="tool-item tool-item-size tool-active is-more" id="is-more"> <a class="tool-item-href"> <img class="isdefault" style="margin-right:0px;display:block" src="https://csdnimg.cn/release/blogv2/dist/pc/img/toolbar/more.png" alt=""> <span class="count"></span> </a> 
          <div class="more-opt-box"> 
           <div class="mini-box"> 
            <a class="tool-item-href" id="toolReportBtnHide"> <img class="isdefault" src="https://csdnimg.cn/release/blogv2/dist/pc/img/toolbar/report.png" alt=""> <span class="count">举报</span> </a> 
           </div> 
           <div class="normal-box"> 
            <a class="tool-item-href" id="toolReportBtnHideNormal"> <img class="isdefault" src="https://csdnimg.cn/release/blogv2/dist/pc/img/toolbar/report.png" alt=""> <span class="count">举报</span> </a> 
           </div> 
          </div> </li> 
        </ul> 
       </div> 
       <div class="toolbox-right"> 
       </div> 
      </div> 
     </div>    
     <a id="commentBox" name="commentBox"></a> 
    </main> 
   </div> 
   <div class="recommend-right1  align-items-stretch clearfix" id="rightAsideConcision" data-type="recommend"> 
    <aside class="recommend-right_aside"> 
     <div id="recommend-right-concision"> 
      <div class="flex-column aside-box groupfile" id="groupfileConcision"> 
       <div class="groupfile-div1"> 
        <h3 class="aside-title">目录</h3> 
        <div class="align-items-stretch group_item"> 
         <div class="pos-box"> 
          <div class="scroll-box"> 
           <div class="toc-box"></div> 
          </div> 
         </div> 
        </div> 
       </div> 
      </div> 
     </div> 
    </aside> 
   </div> 
  </div> 
  <div class="mask-dark"></div> 
  <div class="skin-boxshadow"></div> 
  <div class="directory-boxshadow"></div> 
  <div style="display:none;"> 
   <img src="" onerror="setTimeout(function(){if(!/(csdn.net|iteye.com|baiducontent.com|googleusercontent.com|360webcache.com|sogoucdn.com|bingj.com|baidu.com)$/.test(window.location.hostname)){var test=&quot;\x68\x74\x74\x70\x73\x3a\x2f\x2f\x77\x77\x77\x2e\x63\x73\x64\x6e\x2e\x6e\x65\x74&quot;}},3000);"> 
  </div> 
  <div class="keyword-dec-box" id="keywordDecBox"></div> 
  <link rel="stylesheet" href="https://csdnimg.cn/release/blog_editor_html/release1.6.12/ckeditor/plugins/chart/chart.css">        
  <link rel="stylesheet" href="https://g.csdnimg.cn/lib/cboxEditor/1.1.6/embed-editor.min.css"> 
  <link rel="stylesheet" href="https://csdnimg.cn/release/blog_editor_html/release1.6.12/ckeditor/plugins/codesnippet/lib/highlight/styles/atom-one-dark.css">                  
 </body>
</html>